package com.casic.ops.runner.ssh;

import cn.hutool.core.io.file.PathUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.casic.ops.consts.ResultCode;
import com.casic.ops.entity.domain.MachineInfoDO;
import com.casic.ops.entity.dto.pipeline.datastructure.constant.CommandConst;
import com.casic.ops.runner.pipeline.node.NodeConst;
import com.casic.ops.utils.ValueMix;
import com.google.protobuf.ServiceException;
import com.jcraft.jsch.*;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName ops
 * @Description ssh 的命令操作的集合 ,这里是做个统一,其他pipleline 和web ternminal 的实现方式不同
 * @Author mianbin
 * @Date 2022/6/22 15:43
 * @Version 1.0
 **/
public class SshCommand implements SshClient {

    /**
     * jsch session
     */
    Session session;
    

    /**
     * 基于用户名密码认证的构造器
     *
     * @param username 用户名
     * @param password 密码
     * @param host     主机ip
     * @param port     ssh端口号
     * @throws JSchException
     */

    public SshCommand(String username, String password, String host, int port) throws JSchException {
        JSch jsch = new JSch();
        session = jsch.getSession(username, host, port);
        session.setConfig("PreferredAuthentications", "password");
        session.setConfig("StrictHostKeyChecking", "no");
        session.setPassword(password);
        session.connect();

    }

    /**
     * 基于用户名密码认证的构造器
     * Machine实体类
     *
     * @throws JSchException
     */
    public SshCommand(MachineInfoDO machine) throws JSchException {
        JSch jsch = new JSch();
        // 根据用户名，主机ip，端口获取一个Session对象
        session = jsch.getSession(machine.getUsername(), machine.getMachineHost(), machine.getSshPort());
        session.setConfig("PreferredAuthentications", "password");
        session.setConfig("StrictHostKeyChecking", "no");
        String decrypt = ValueMix.decrypt(machine.getPassword());
        session.setPassword(decrypt);
        // 通过Session建立链接
        session.connect();
    }

    @Override
    public void disconnect() {
        session.disconnect();
    }

    @Override
    public int exec(String command, ExecCallback execCallback) throws IOException {

        ChannelShell channel = null;
        try {
            channel = (ChannelShell) session.openChannel("shell");
            channel.connect();
        } catch (JSchException e) {
            e.printStackTrace();
        }

        InputStream inputStream = channel.getInputStream();
        OutputStream outputStream = channel.getOutputStream();
        PrintWriter printWriter = new PrintWriter(outputStream);

        printWriter.println(command);

        printWriter.println("exit");
        printWriter.flush();
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));

        String msg = null;
        while ((msg = in.readLine()) != null) {
            execCallback.callback(msg);
        }
        int result = channel.getExitStatus();

        in.close();

        return result;
    }


    @Override
    public int exec(List<String> commands, ExecCallback execCallback) throws IOException {

        ChannelShell channel = null;
        try {
            channel = (ChannelShell) session.openChannel("shell");
            channel.connect();
        } catch (JSchException e) {
            e.printStackTrace();
        }

        InputStream inputStream = channel.getInputStream();
        OutputStream outputStream = channel.getOutputStream();
        PrintWriter printWriter = new PrintWriter(outputStream);

        for (String command : commands) {
            printWriter.println(command);
        }


        printWriter.println("exit");
        printWriter.flush();
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));

        String msg = null;
        while ((msg = in.readLine()) != null) {
            execCallback.callback(msg+CommandConst.ENTER);
        }
        while (true) {
            if (channel.isClosed()) {
                break;
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        int result = channel.getExitStatus();

        in.close();
        channel.disconnect();

        return result;
    }
}
